home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / Weather / Weather.app / state.c < prev    next >
C/C++ Source or Header  |  1992-07-01  |  8KB  |  351 lines

  1. /*
  2.  * State machine and menu abstraction.
  3.  * The idea is to keep as much of the hookup dialog
  4.  * as possible in a text file, so that menus and hookup protocols
  5.  * are easy to change here or in other apps.
  6.  * It has grown a few warts.
  7.  *
  8.  * M. J. Hawley
  9.  * mike@media-lab.mit.edu
  10.  * Copyright (c) November 1991, MIT Media Laboratory.
  11.  */
  12.  
  13. #define MENU 1
  14. typedef enum { Plain, Pattern, Status, Goto, FlushS, Pause, CmdS } SType;
  15.  
  16. typedef struct String {
  17.     char *s;
  18.     struct String *next;
  19. } String;
  20.  
  21. typedef struct MenuItem {
  22.     char *send, *get, *label;
  23.     struct MenuItem *next;
  24. } MenuItem;
  25.  
  26. typedef struct {
  27.     int type;
  28.     char *name;
  29.     char *first, *last, *label;
  30.     String *l;
  31.     MenuItem *m;
  32. } State;
  33.  
  34. #include "util.h"
  35.  
  36. SType lastType = Plain;
  37.  
  38. char *getStr(s,t) char *s, *t; {
  39.     char end = ' ';
  40.  
  41.     *t = '\0';
  42.     s = skipsp(s);
  43.     lastType = Plain;
  44.     switch (*s){
  45.     Case '/': lastType = Pattern;
  46.     Case '+': lastType = Status; s++;
  47.     Case '!': lastType = CmdS; s++;
  48.     Case ',': lastType = FlushS; s++;
  49.     Case '=': lastType = Goto; s = skipsp(s+2);
  50.     }
  51.  
  52.     if (*s=='/' || *s == '"') end = *s++;
  53.     while (*s && !(*s == end || (end==' ' && *s == '\t'))){
  54.         *t = *s++;
  55.         if (*t == '\\') switch (*s){
  56.             Case 'n': *t = '\n'; s++;
  57.             Case 't': *t = '\t'; s++;
  58.             Case 'b': *t = '\b'; s++;
  59.             Default : *t = *s; s++;
  60.         }
  61.         t++;
  62.     }
  63.     *t = '\0';
  64.     if (*s && *s != ' ' && *s != '\t') ++s;
  65.     if (*s) s = skipsp(s);
  66.     return s;
  67. }
  68.  
  69. State *
  70. newMenu(s) char *s; {
  71.     State *S = Alloc(State);
  72.     char n[1024], first[1024], last[1024], label[1024];
  73.     s = skipsp(skipsp(s)+4);
  74.     sscanf(s,"%[^:]",n);
  75.     s = skipsp(index(s,':')+1);
  76.     s = getStr(s,first);
  77.     s = getStr(s,last);
  78.     s = getStr(s,label); 
  79.     S->name = save(n);
  80.     S->label = save(label);
  81.     S->first = save(first);
  82.     S->last = save(last);
  83.     S->type = MENU;
  84.     return S;
  85. }
  86.  
  87. State *
  88. newState(s) char *s; {
  89.     State *S = Alloc(State);
  90.     S->name = save(s);
  91.     return S;
  92. }
  93.  
  94. String *
  95. addStr(s,t) String *s; char *t; {
  96.     String *start = s, *n = Alloc(String);
  97.     char *p;
  98.     
  99.     p = n->s = save(t);
  100.     if (*p=='/' && (p = index(p+1,'/'))){
  101.         while (p[-1]=='\\') p = index(p+1,'/');
  102.         if (p) *p = '\0';
  103.     }
  104.     
  105.     if (!s) return n;
  106.     while (s->next) s = s->next;
  107.     s->next = n;
  108.     return start;
  109. }
  110.  
  111. stripq(s) char *s; {
  112.     if (*s == '\"'){
  113.         strcpy(s,s+1);
  114.         if (s = rindex(s,'\"')) *s = '\0';
  115.     }
  116. }
  117.  
  118. void
  119. addMenu(S,s) State *S; char *s; {
  120.     char send[1024], get[1024], label[1024];
  121.     MenuItem *m = Alloc(MenuItem), *t;
  122.     s = getStr(s,send); m->send = save(send);
  123.     s = getStr(s,get); m->get = save(get);
  124.     skipsp(s); strcpy(label,s); stripnl(label); stripq(label); m->label = save(label);
  125.     for (t=S->m; t && t->next; t = t->next) ;
  126.     if (t) t->next = m; else S->m = m;
  127. }
  128.  
  129. void
  130. addString(S,s) State *S; char *s; {
  131.     stripnl(s=skipsp(s));
  132.     S->l = addStr(S->l,s);
  133. }
  134.  
  135. #define MaxS 256
  136. static State *ST[MaxS];
  137. static int NS = 0;
  138.  
  139. void
  140. readState(f) FILE *f; {
  141.     char s[1024], n[1024];
  142.     State *S = (State *)0;
  143.     while (fgets(s,sizeof s,f)){
  144.         stripcomment(s);
  145.         if (blank(s)) continue;
  146.         if (strncmp(s,"Menu",4)==0){
  147.             S = newMenu(s);
  148.             ST[NS++] = S;
  149.         } else
  150.         if (match(s,"[a-zA-Z]*:")){
  151.             sscanf(s,"%[^:]",n);
  152.             S = newState(n);
  153.             ST[NS++] = S;
  154.         } else
  155.         if (S){
  156.             if (S->type == MENU) addMenu(S,s); else
  157.                                  addString(S,s);
  158.         }
  159.     }
  160. }
  161.  
  162. State*
  163. state(s) char *s; {
  164.     int i;
  165.     s = skipsp(s);
  166.     for (i=0;i<NS;i++)
  167.         if (strcmp(s,ST[i]->name)==0) return ST[i];
  168.     return (State *)0;
  169. }
  170.  
  171. char *str(s) char *s; { return s? s : ""; }
  172.  
  173. void
  174. printState(s) State *s; {
  175.     if (!s) return printf("huh?\n");
  176.     printf("%s: %s %s %s\n",s->name,str(s->first),str(s->last),str(s->label));
  177. }
  178.  
  179. void
  180. ReadState(s) char *s; {
  181.     FILE *f;
  182.     if (!NS){
  183.         f = fopen(s,"r");
  184.         if (f) readState(f), fclose(f);
  185.     }
  186.     setState("Attach");
  187.     setMenu("Main");
  188. }
  189.  
  190. State *curState = (State *)0;
  191.  
  192. void
  193. setState(s) char *s; {
  194.     curState = state(s);
  195.     if (strcmp(s,"Detach")==0) logout();
  196.     if (strcmp(s,"Ready")==0) fetchReports();
  197. }
  198.  
  199. void
  200. execute(s) char *s; {
  201.     char t[1024];
  202.  
  203.     if (s[0]=='/') s += strlen(s)+1;
  204.     while ((s=getStr(s,t)) && *t) switch (lastType){
  205.         Case CmdS:    Command(t);
  206.         Case Status : message(t);
  207.         Case Plain  : if (!state(t)) Put("%s",t);
  208.         Case FlushS : Flush(t);
  209.         Case Goto   : setState(t);
  210.     }
  211. }
  212.  
  213. void
  214. execState(s,t) State *s; char *t; {
  215.     String *l;
  216.     if (!s) s = curState;
  217.     if (!s || !s->l) return;
  218.     for (l=s->l; l; l=l->next){
  219.         if (l->s[0]!='/') execute(l->s);
  220.         else
  221.         if (l->s[0]=='/' && *t && match(t,l->s+1)) execute(l->s);
  222.     }
  223. }
  224.  
  225. void
  226. runState(s) char *s; {
  227.     execState(curState,s);
  228. }
  229.  
  230. int numItem(s) char *s; {
  231.     int i = 0;
  232.     State *S = state(s);
  233.     MenuItem *m;
  234.     if (!S) return 0;
  235.     for (m=S->m; m; m=m->next) i++;
  236.     return i;
  237. }
  238.  
  239. State *curMenu;
  240.  
  241. setMenu(s) char *s; { curMenu = state(s); }
  242.  
  243. MenuItem *
  244. curMenuItem(n) int n; {
  245.     MenuItem *m;
  246.     if (!curMenu) return (MenuItem *)0;
  247.     for (m=curMenu->m; m && n-->0; m = m->next) ;
  248.     return m;
  249. }
  250.  
  251. valid(m) MenuItem *m; {
  252.     MenuItem *t;
  253.     if (!curMenu) return 0;
  254.     for (t=curMenu->m; t; t=t->next)
  255.         if (t==m) return 1;
  256.     return 0;
  257. }
  258.  
  259.  
  260. char *getLabel(m) MenuItem *m; { return valid(m)? m->label : ""; }
  261. char *getSend(m) MenuItem *m; { return valid(m)? m->send : ""; }
  262. char *getGet(m) MenuItem *m; { return valid(m)? m->get : ""; }
  263. char *curMenuFirst() { return curMenu? curMenu->first : "**nada**"; }
  264. char *curMenuLast() { return curMenu? curMenu->last : "**nada**"; }
  265.  
  266. char *
  267. getReport(buf) char *buf; {
  268.     char *p = buf+1;
  269.     int starting = 1;
  270.     strcpy(buf,"\n");
  271.     while (pgets(p,1024) && !strindex(p,curMenuFirst())){
  272.     if (Verbose) printf("+%s",p);
  273.     if (starting && strlen(p)<=5)
  274.         ;
  275.     else
  276.     if (strindex(p,"Enter 3-letter") || strindex(p,"Enter 2-letter")
  277.             || strindex(p,"Selection:"))
  278.         ;
  279.     else
  280.     if (strindex(p,"ress return") || strindex(p,"ress Return"))
  281.         Put("\n");
  282.     else
  283.         starting = 0, p += strlen(p);
  284.     }
  285.     *p = '\0';
  286.     if (curMenu) Flush(curMenuLast());
  287.     return buf;
  288. }
  289.  
  290. MenuItem *
  291. menuFor(label,name) char *label, *name; {
  292.     int i;
  293.     MenuItem *m;
  294.     *name = '\0';
  295.     for (i=0;i<NS;i++){
  296.         if (ST[i]->type == MENU){
  297.             for (m=ST[i]->m;m;m=m->next)
  298.                 if (strcmp(label,m->label)==0){
  299.                     strcpy(name,ST[i]->name);
  300.                     return m;
  301.                 }
  302.         }
  303.     }
  304.     return (MenuItem *)0;
  305. }
  306.  
  307. #define hackflush() sleep(1); while (pgets(hack,1024) && !strindex(hack,curMenuLast())) if (Verbose) printf("+%s",hack)
  308.  
  309. void
  310. fetchReport(label,buf) char *label, *buf; {
  311.     char menu[256];
  312.     char hack[1024];
  313.     MenuItem *m = menuFor(label,menu);
  314.     *buf = '\0';
  315.     if (!m) return;
  316.  
  317.     {
  318.         State *s = state("Main");
  319.         MenuItem *t = s->m;
  320.         for (;t && strcmp(t->get,menu);t=t->next) ;
  321.         if (t)
  322.             Put("%s",t->send);
  323.     }
  324.     setMenu(menu); hackflush();
  325.     Put("%s",m->send);
  326.     if (strcmp(menu,"Main")==0) pgets(hack,1024);
  327.     getReport(buf);
  328.     if (strcmp(curMenu->name,"Main")){
  329.         Put("m\n"), setMenu("Main");
  330.         hackflush();
  331.     } else
  332.         hackflush();
  333. }
  334.  
  335. /*
  336.  
  337. print(){
  338.     int i;
  339.     for (i=0;i<NS;i++) printState(ST[i]);
  340. }
  341.  
  342. main(){
  343.     char s[1024];
  344.     ReadState("states");
  345.     print();
  346.     setState("Attach");
  347.     *s = '\0';
  348.     do { runState(s); } while (gets(s));
  349. }
  350. */
  351.